; randBMP: A random bitmap generator
; Copyright (C) 2010 Erik Weatherwax

; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.

; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.

; You should have received a copy of the GNU General Public License
; along with this program.  If not, see <http://www.gnu.org/licenses/>.

%include "writeHeader.asm"

extern	atoi, malloc, free

section .data	
	RAND_SOURCE	db	"/dev/urandom"

section .bss
	filesize	resd	1
	width		resd	1
	height		resd	1
	bytesPerRow	resd	1
	datasize	resd	1
	dataPtr		resd	1	
	randFile	resd	1
	createdFile	resd	1

section .text
	global main

main:
	; dynamically determine width and height from CL parameters
	
	; stack: [frame ptr] [argc] [argv]
	; argv: [prm name] [file name] [width] [height]

	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	

	mov	eax, [esp + 8]			; argv
	add	eax, 8				; argv + 2
	mov	edx, [eax]			; *(argv + 2) = argv[2]
	push	edx				; width as a char*
	call	atoi				; should give us integer width in eax
	pop	edx				; clear stack
	mov	DWORD [width], eax		

	;; compute bytes needed
	movzx	ebx, WORD [BITS_PER_PX]
	mul	ebx				; width is already in eax
	shr	eax, 3				; bits to bytes
 
	;; calculate padding bytes
	mov	ebx, eax			; copy width byte count to ebx
	and	eax, 0x3			; mask off remainder bits mod 4
	jz	noPad
	sub	eax, 4				; -number of bytes in remainder
	neg	eax				; eax: number of bytes in remainder
	add	ebx, eax			; add padding bytes
noPad:	
	mov	DWORD [bytesPerRow], ebx
	;; ;;;;;;;;;;;;;;;;;;;;;;;;

	mov	eax, [esp + 8]			; argv
	add	eax, 12				; argv + 3
	mov	edx, [eax]			; *(argv + 3) = argv[3] in eax
	push	edx
	call	atoi
	pop	edx
	mov	DWORD [height], eax

	mov	ebx, [bytesPerRow]		; height is already in eax
	mul	ebx				; bytes per row * height = bytes needed in eax
	
	mov	DWORD [datasize], eax
	add	eax, [HEAD_SIZE]		; compensate for header
	mov	DWORD [filesize], eax

	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	; create a new file
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
						
	mov	eax, [esp + 8]			; argv
	add	eax, 4				; argv + 1
	mov	ebx, [eax]			; *(argv + 1) = argv[1]
						; pass filename to fileCreate in ebx
	call	fileCreate			; on success, we have a file descriptor in eax
	mov	DWORD [createdFile], eax  	; save file descriptor for created bitmap
	
	; writeHeader(int fd, int filesize, int datasize, int width, int height)
	; uses stdcall syntax -- all args go on stack
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	push	DWORD [height]
	push	DWORD [width]
	push	DWORD [datasize]
	push	DWORD [filesize]
	push	DWORD [createdFile]	
	call	writeHeader			; copy header to new file
						; writeHeader is an ASM routine that cleans the stack itself
	
	; allocate heap memory as needed for datasize
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	push	DWORD [datasize]		
	call	malloc				; we have a pointer to beginning of heap mem seg. in eax
	mov	DWORD [dataPtr], eax		; save allocated memory for data
	add	esp, 4				; clear stack 

	; read random bytes from random source and write to bitmap file
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
				
	call	openRandSource			; open source of random bytes
	mov	DWORD [randFile], eax		; save file descriptor for random source
		
	call	getRandBytes
	call	writeRandBytes

	; clean up after ourselves

	call	cleanUp			
	jmp	EXIT_NO_ERR

cleanUp:
	; close files used
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	mov	eax, 6			; sys_close
	mov	ebx, [createdFile]	
	int	0x80			; close newly created bitmap

	mov	eax, 6
	mov	ebx, [randFile]
	int	0x80			; close random source

	; deallocate heap memory
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	push	DWORD [dataPtr]		; pointer to allocated heap block to clear
	call	free
	add	esp, 4			; clear stack

	ret	

fileCreate:
	mov	eax, 8			; sys_creat
	mov	ecx, 00644Q		; file permissions
	int	0x80

	test	eax, eax
	js	EXIT_WITH_ERR

	ret

openRandSource:
	mov	eax, 5			; sys_open
	mov	ebx, RAND_SOURCE
	xor	ecx, ecx
	mov	edx, 00644Q
	int	0x80
	
	test	eax, eax		; valid file descriptor?
	js	EXIT_WITH_ERR

	ret

getRandBytes:
	mov	eax, 3			; sys_read
	mov	ebx, [randFile]
	mov	ecx, [dataPtr]		; address of array to write to
	mov	edx, [datasize]		; get needed number of random bytes
	int	0x80
	ret

writeRandBytes:
	mov	eax, 4			; sys_write
	mov	ebx, [createdFile]	; write to created file
	mov	ecx, [dataPtr]		; array of bytes to write
	mov	edx, [datasize]		
	int	0x80
	ret

EXIT_NO_ERR:
	mov	eax, 1
	mov	ebx, 0
	int	0x80

EXIT_WITH_ERR:
	mov	eax, 1
	mov	ebx, 1
	int	0x80


